//
//  CLLTimer.swift
//  DemoNavBar
//
//  Created by YangHuan on 2019/12/13.
//  Copyright © 2019 YangHuan. All rights reserved.
//
//定时器 和 倒计时封装

import Foundation

/// 定时器
public final class CLLTimer {
    private let internalTimer: DispatchSourceTimer
    
    private var isRunning: Bool = false
    
    private let repeats: Bool
    
    public typealias CLLTimerHandel = (CLLTimer) -> Void
    
    private var handler: CLLTimerHandel
    
    /// 创建定时器
    ///
    /// - Parameters:
    ///   - interval: 间隔时间
    ///   - immediate: 是否直接开始倒计时
    ///   - repeats: 是否循环
    ///   - leeway: 容忍时间误差
    ///   - afterTime: 不直接开始时，延迟开始的时间
    ///   - queue: 线程
    ///   - handler: 回调
    public init(interval: DispatchTimeInterval, immediate: Bool = true, repeats: Bool = false, leeway: DispatchTimeInterval = .seconds(0), afterTime: DispatchTimeInterval = .seconds(0) ,queue: DispatchQueue = .main , handler: @escaping CLLTimerHandel) {
        self.handler = handler
        self.repeats = repeats
        internalTimer = DispatchSource.makeTimerSource(queue: queue)
        internalTimer.setEventHandler {[weak self] in
            if let strongSelf = self {
                handler(strongSelf)
            }
        }
        if repeats {
            if immediate {
                internalTimer.schedule(wallDeadline: .now(), repeating: interval, leeway: leeway)
            } else {
                internalTimer.schedule(wallDeadline: .now() + afterTime, repeating: interval, leeway: leeway)
            }
        } else {
            internalTimer.schedule(wallDeadline: .now(), leeway: leeway)
        }
    }
    
    /// 直接开始的定时器
    public static func repeaticTimer(interval: DispatchTimeInterval, leeway: DispatchTimeInterval = .seconds(0), queue: DispatchQueue = .main , handler: @escaping CLLTimerHandel ) -> CLLTimer {
        return CLLTimer(interval: interval, repeats: true, leeway: leeway, queue: queue, handler: handler)
    }
    
    /// 延迟开始的定时器
    public static func repeaticTimer(interval: DispatchTimeInterval, leeway: DispatchTimeInterval = .seconds(0), afterTime: DispatchTimeInterval, queue: DispatchQueue = .main , handler: @escaping CLLTimerHandel ) -> CLLTimer {
        return CLLTimer(interval: interval, immediate: false, repeats: true, leeway: leeway, afterTime: afterTime, queue: queue, handler: handler)
    }
    
    deinit {
        if !self.isRunning {
            internalTimer.resume() //这样之后置空才不会崩溃
        }
    }
    
    public func fire() {
        if repeats {
            handler(self)
        } else {
            handler(self)
            internalTimer.cancel()
        }
    }
    
    /// 开始
    public func start() {
        if !isRunning {
            internalTimer.resume()
            isRunning = true
        }
    }
    
    /// 暂停
    public func suspend() {
        if isRunning {
            internalTimer.suspend()
            isRunning = false
        }
    }
    
    public func rescheduleHandler(handler: @escaping CLLTimerHandel) {
        self.handler = handler
        internalTimer.setEventHandler { [weak self] in
            if let strongSelf = self {
                handler(strongSelf)
            }
        }
        
    }
}


/// 倒计时，注意循环引用
public class YKCountdownTimer {
    private let internalTimer: CLLTimer
    private(set) var leftTimes: Int
    private let originalTimes: Int
    private let handler: (YKCountdownTimer, _ leftTimes: Int) -> Void
    
    public init(interval: DispatchTimeInterval = DispatchTimeInterval.seconds(1), times: Int, queue: DispatchQueue = .main , handler:  @escaping (YKCountdownTimer, _ leftTimes: Int) -> Void ) {
        
        self.leftTimes = times
        self.originalTimes = times
        self.handler = handler
        self.internalTimer = CLLTimer.repeaticTimer(interval: interval, queue: queue, handler: { _ in
        })
        self.internalTimer.rescheduleHandler { [weak self]  timer in
            if let strongSelf = self {
                if strongSelf.leftTimes > 0 {
                    strongSelf.leftTimes = strongSelf.leftTimes - 1
                    strongSelf.handler(strongSelf, strongSelf.leftTimes)
                } else {
                    strongSelf.internalTimer.suspend()
                }
            }
        }
    }
    
    public func start() {
        self.internalTimer.start()
    }
    
    public func suspend() {
        self.internalTimer.suspend()
    }
    
    public func reCountDown() {
        self.leftTimes = self.originalTimes
    }
    
}




